利用 Docker 在不同宿主机做 CentOS 系统容器 | 原力计划
最近公司新接到一个项目,惯例是通过技术架构、业务需求、用户量还有以往的经验大概评估出一份资源配置表格提供给客户,让客户参考采购的服务器资源。但这次客户根本没有根据我们提供的参考表格来,而是直接就提供给我们一些高配置的服务器实例,实例数与我们预期的少了很多,但配置相对的提高了很多,本着客户是上帝的原则,我们只能自己针对服务器做虚拟化。
我为什么选择用Docker虚拟化服务器?
之前一直是在Windows系统上做虚拟机,在Linux系统上虚拟化服务器还是第一次,更何况这个Linux系统是没有图形界面的。在虚拟化服务器之前我也查询资料做过很多技术比较,最终选择使用Docker来虚拟化服务器,具体总结优势无非以下几点:
1、Docker创建的容器启动速度快,秒级启动。
Docker管理容器操作(start、stop、rm、restart等等) 都是以秒或毫秒为单位的。
2、Docker可以基于创建的镜像进行弹性扩展。
创建容器并且根据自己的需求配置好容器后提交镜像到仓库,等到需要扩展容器的时候可拉取镜像启动相同的容器。
3、Docker创建的容器较轻量级
我可以在一台服务器上启动很多容器,如果只是用到某个服务的话,你无需虚拟整套系统版本。当然本文目的是虚拟出一整套系统的运行环境,所以就另当别论了。
4、Docker开源免费
开源的,免费的,低成本的,这就不用我多说了。
Docker的安装
Docker的安装这个其实我不必多说什么,网上一搜一大堆。但是有几点我需要说明下:
1、Docker存储数据位置及镜像存储位置
默认情况下Docker是将数据存储在/var/lib/docker路径下的,如果你系统盘的磁盘空间比较小,那你就需要修改Docker的数据存储路径了,可通过如下命令查看:
sudo docker info | grep "Docker Root Dir"
修改方法就是先停掉Docker服务,然后在/etc/docker/路径下创建一个daemon.json文件,在文件里加入如下文本:
"graph": "/home/docker"
}
2、拉取私有仓库镜像
这个私有仓库不是Docker收费版的那个,而是针对自己公司搭建的私有仓库。当你想拉取私有仓库镜像的时候,你需要配置私有仓库的IP和端口号,目的是让Docker信任你的私有仓库。具体步骤还是先关闭Docker服务,然后修改daemon.json文件,如下:
"graph": "/home/docker",
"insecure-registries":["192.168.10.123:5000"]
}
Docker容器在不同宿主机间通信
在说这个之前我先大概说下Docker网络配置,Docker安装后会自动创建3种网络:bridge、host、none,这三种网络模式的详细讲解我就不说了,因为太占篇幅,我就大概讲下我的理解吧。如下:
1、bridge模式
我理解就是Docker守护进程启动时会在宿主机上创建一个docker0虚拟网桥,这个网桥的作用就相当于一个交互机,该宿主机上的所有容器都是通过这个虚拟网桥连接外部网络的,docker0虚拟网桥的IP就相当于该宿主机上所有容器的默认网关。
当创建一个新容器时Docker会在宿主机上创建一对虚拟网卡veth pair设备,并且将veth pair设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在宿主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到docker0网桥中。
该模式是Docker创建容器的默认模式,如果想让外部网络访问到容器中的服务,就是需针对端口做映射,归根究底它实际是在iptables做了DNAT规则,实现端口转发功能。本文也是使用的这个模式。
根据我使用这么长时间的经验来看,这种模式的缺点就是需要事先规划好容器哪些端口该做映射。网上也有教在容器创建好后给容器增添映射端口,但是有的不靠谱儿,有的则是需要修改Docker生成的配置文件,但是如果像我这种构建的是整套系统运行环境,修改配置后重启可能有些服务就需要重新配置了,比如集群相关的服务。
2、host模式
这种模式其实就是和宿主机共用一套网路环境,它使用的IP就是宿主机的IP,它使用的端口也是宿主机的端口,网络的隔离性不好,我没有使用它的根本原因也正是它的隔离性,因为我所使用的宿主机上是存在两台系统运行环境的,或多或少的会出现端口冲突问题。
3、none模式
这种模式下的容器没有网卡、IP、路由等信息。需要我们自己为Docker容器添加网卡、配置IP等。也就是说它没有办法联网,我至今还没有用过,可能这样更安全吧。
以上就是我对Docker安装后创建的三种网络模式的理解,还有两种模式(container模式和user-defined模式)可以自行查找了解。
3.1、不同宿主机间容器通信原理图
上图为不同宿主机间容器通信的的原理图,说实话这张图在网上都被用烂了,但是没得办法,谁让咱确实是按照这么做的呢,对于上图的讲解我也是直接照搬网上查到的,如下:
1)数据从源容器中发出后,经由所在主机的docker0虚拟网卡转发到flannel0虚拟网卡,这是个P2P的虚拟网卡,flanneld服务监听在网卡的另外一端。
2)Flannel通过Etcd服务维护了一张节点间的路由表,在稍后的配置部分我们会介绍其中的内容。
3)源主机的flanneld服务将原本的数据内容UDP封装后根据自己的路由表投递给目的节点的flanneld服务,数据到达以后被解包,然后直接进入目的节点的flannel0虚拟网卡,
然后被转发到目的主机的docker0虚拟网卡,最后就像本机容器通信一下的有docker0路由到达目标容器。
这样整个数据包的传递就完成了,这里需要解释三个问题:
1)UDP封装是怎么回事?
在UDP的数据内容部分其实是另一个ICMP(也就是ping命令)的数据包。原始数据是在起始节点的Flannel服务上进行UDP封装的,投递到目的节点后就被另一端的Flannel服务
还原成了原始的数据包,两边的Docker服务都感觉不到这个过程的存在。
2)为什么每个节点上的Docker会使用不同的IP地址段?
这个事情看起来很诡异,但真相十分简单。其实只是单纯的因为Flannel通过Etcd分配了每个节点可用的IP地址段后,偷偷的修改了Docker的启动参数。
在运行了Flannel服务的节点上可以查看到Docker服务进程运行参数(ps aux|grep docker|grep “bip”),例如“–bip=182.48.56.1/24”这个参数,它限制了所在节点容器获得的IP范围。这个IP范围是由Flannel自动分配的,由Flannel通过保存在Etcd服务中的记录确保它们不会重复。
3)为什么在发送节点上的数据会从docker0路由到flannel0虚拟网卡,在目的节点会从flannel0路由到docker0虚拟网卡?
例如现在有一个数据包要从IP为172.17.18.2的容器发到IP为172.17.46.2的容器。根据数据发送节点的路由表,它只与172.17.0.0/16匹配这条记录匹配,因此数据从docker0出来以后就被投递到了flannel0。同理在目标节点,由于投递的地址是一个容器,因此目的地址一定会落在docker0对于的172.17.46.0/24这个记录上,自然的被投递到了docker0网卡。
3.2、不同宿主机间容器通信安装部署
虽然安装部署方法也是在网上找的,但是网上给出的方法大方向是没问题的就是一些细节讲的还不是很清楚,导致我部署的时候还是出现很多问题。下面我会将我安装部署的过程和遇到的问题整理到本文中。
3.2.1、宿主机环境准备
我准备了四台宿主机,如下:
四台宿主机都需要设置hosts:
192.168.10.1 master
192.168.10.1 etcd
192.168.10.2 slave1
192.168.10.3 slave2
192.168.10.4 slave3
本来想搭建etcd的多主机集群的,但是想了下只是在预生产使用而且只是处在前期搭建状态还没有正式使用,所以etcd我只在192.168.10.1服务器上搭建了单个主机的,如果后期出现问题,我会修改为多主机集群。
1、安装etcd服务
#ETCD_CORS=""
ETCD_DATA_DIR="/var/lib/etcd/default.etcd" #数据存放路径
#ETCD_WAL_DIR=""
#ETCD_LISTEN_PEER_URLS="http://localhost:2380"
ETCD_LISTEN_CLIENT_URLS="http://0.0.0.0:2379,http://0.0.0.0:4001" #监听客户端地址
#ETCD_MAX_SNAPSHOTS="5"
#ETCD_MAX_WALS="5"
ETCD_NAME="master" #部署节点的名称
#ETCD_SNAPSHOT_COUNT="100000"
#ETCD_HEARTBEAT_INTERVAL="100"
#ETCD_ELECTION_TIMEOUT="1000"
#ETCD_QUOTA_BACKEND_BYTES="0"
#ETCD_MAX_REQUEST_BYTES="1572864"
#ETCD_GRPC_KEEPALIVE_MIN_TIME="5s"
#ETCD_GRPC_KEEPALIVE_INTERVAL="2h0m0s"
#ETCD_GRPC_KEEPALIVE_TIMEOUT="20s"
#
#[Clustering]
#ETCD_INITIAL_ADVERTISE_PEER_URLS="http://localhost:2380"
ETCD_ADVERTISE_CLIENT_URLS="http://etcd:2379,http://etcd:4001" #通知客户端地址
#ETCD_DISCOVERY=""
[root@master ~]# systemctl enable etcd.service
tcp 0 0 127.0.0.1:2380 0.0.0.0:* LISTEN 22733/etcd
tcp6 0 0 :::4001 :::* LISTEN 22733/etcd
[root@master ~]# ps -ef | grep etcd
etcd 22733 1 1 4月17 ? 03:33:44 /usr/bin/etcd --name=master --data-dir=/var/lib/etcd/default.etcd --listen-client-urls=http://0.0.0.0:2379,http://0.0.0.0:4001
root 162335 1 0 4月22 ? 00:04:37 /usr/bin/flanneld -etcd-endpoints=http://etcd:2379 -etcd-prefix=/atomic.io/network
root 333684 333652 0 19:58 pts/2 00:00:00 vi /etc/etcd/etcd.conf
root 334263 333652 0 20:00 pts/2 00:00:00 vi /etc/etcd/etcd.conf
root 338219 333652 0 20:14 pts/2 00:00:00 grep --color=auto etcd
[root@master ~]# etcdctl -C http://etcd:4001 cluster-health
member 8e9e05c52164694d is healthy: got healthy result from http://etcd:2379
cluster is healthy
[root@master ~]# etcdctl -C http://etcd:2379 cluster-health
member 8e9e05c52164694d is healthy: got healthy result from http://etcd:2379
cluster is healthy
[root@master ~]#
{ "Network": "172.18.0.0/16" }
flannel是所有宿主机需要安装的中间件,而且前文中提到的hosts文件一定要设置好。
1、安装flannel服务
# Flanneld configuration options
# etcd url location. Point this to the server where etcd runs
FLANNEL_ETCD_ENDPOINTS="http://etcd:2379" #etcd客户端端口
# etcd config key. This is the configuration key that flannel queries
# For address range assignment
FLANNEL_ETCD_PREFIX="/atomic.io/network" #这个参数的值需要是etcd保存的key值,不然flannel启动不了
# Any additional options that you want to pass
#FLANNEL_OPTIONS=""
3、启动flanneld服务
[root@master ~]# systemctl enable flanneld.service
root 162335 1 0 4月22 ? 00:04:38 /usr/bin/flanneld -etcd-endpoints=http://etcd:2379 -etcd-prefix=/atomic.io/network
root 345092 333652 0 20:37 pts/2 00:00:00 vim /etc/sysconfig/flanneld
root 345496 333652 0 20:39 pts/2 00:00:00 vim /etc/sysconfig/flanneld
root 345545 333652 0 20:39 pts/2 00:00:00 vim /etc/sysconfig/flanneld
root 347078 333652 0 20:44 pts/2 00:00:00 vim /etc/sysconfig/flanneld
root 350147 333652 0 20:54 pts/2 00:00:00 grep --color=auto flanneld
[root@master ~]# ifconfig flannel0
flannel0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1472
inet 172.18.92.0 netmask 255.255.0.0 destination 172.18.92.0
inet6 fe80::244d:d95c:a79f:af2d prefixlen 64 scopeid 0x20<link>
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 500 (UNSPEC)
RX packets 2691026 bytes 142959067 (136.3 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2690704 bytes 152477868 (145.4 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
3.2.4、配置docker0虚拟网桥
安装启动flanneld后重启Docker服务,查看Docker服务生成的docker0网桥IP是否已经位于flanneld生成flannel0网卡的网段之中,比如flannel0网卡的IP是:172.18.92.0,docker0的IP是:172.18.92.1,则配置成功。如果IP地址的前三段有一段不同,则说明需要重新对docker0虚拟网桥进行配置,配置方法如下:
1、停掉Docker服务,修改docker.service配置文件
[root@master ~]# vim /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --bip=172.18.92.1/24
2、重启Docker
[root@master ~]# systemctl restart docker
flannel0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1472
inet 172.18.92.0 netmask 255.255.0.0 destination 172.18.92.0
inet6 fe80::244d:d95c:a79f:af2d prefixlen 64 scopeid 0x20<link>
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 500 (UNSPEC)
RX packets 2701666 bytes 143511551 (136.8 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 2701343 bytes 153069980 (145.9 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
[root@master ~]# ifconfig docker0
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.18.92.1 netmask 255.255.255.0 broadcast 172.18.92.255
inet6 fe80::42:cff:fe75:d72 prefixlen 64 scopeid 0x20<link>
ether 02:42:0c:75:0d:72 txqueuelen 0 (Ethernet)
RX packets 4010425 bytes 230843638 (220.1 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3057671 bytes 995135672 (949.0 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
3.2.5、验证宿主机间容器是否通信
如果以上步骤都已配置成功,此时就需要验证不通宿主机间容器是否通信了,验证方法就是在每个宿主机创建个容器,然后在容器中ping其他宿主机中容器的Ip,如果能够ping通,则说明已经完成。如果Ping不通也不要惊慌,因为可能是底层的iptables造成的,所以解决办法是在各宿主机上执行下面操作:
[root@master ~]# iptables -P FORWARD ACCEPT
[root@master ~]# iptables -F
[root@master ~]# iptables -L -n
制作CentOS系统版本容器
1、拉取centos:7.6.1810系统版本的镜像
[root@master ~]# docker run -itd --name pre-centos --privileged=true -p 10022:22 centos:7.6.1810 init
我对该命令中的参数具体讲解下:
-i:以交互模式运行容器,通常与 -t 同时使用。
-t:为容器重新分配一个伪输入终端,通常与 -i 同时使用。
-d:后台运行容器,并返回容器ID,如果不加这个参数,当退出容器时,这个容器也就停止了。
–privileged:默认是false,我们这里改成了true,使用该参数容器中的root拥有真正的root权限,否则容器的root用户只是宿主机的一个普通用户权限,有些命令如:systemctl、service是使用不了的。
-p:就是映射端口的作用
还有一个问题需要注意,就是该命令后的init,加上它赋值给容器真正的root权限才会生效,如果使用/bin/bash是不会生效的。
3、进入创建好的容器
4、安装启动ssh
[root@1fc31e49daxc ~]# systemctl start sshd
5、修改ssh配置文件
#配置信息去掉如下注释
Port 22ListenAddress 0.0.0.0
ListenAddress ::
permitrootlogin yes
UsePAM yes 改为 UsePAM no
GSSAPICleanupCredentials no 改为 GSSAPICleanupCredentials yes
UsePrivilegeSeparation sandbox 改为 UsePrivilegeSeparation no
[root@master ~]# docker commit 1fc31e49daxc pre-centos:1.0
[root@master ~]# docker push 8a1960ed7c4c
10、拉取私有仓库镜像
(注:再次提醒事先规划好容器使用的端口在创建容器,如果容器已经创建成功后想添加端口请查看这篇文章:为已创建的容器添加映射端口)
12、测试容器是否正常运行
[root@slave1 ~]# docker exec -it a38321832cfd bash
14、访问容器
1、如果是在做过容器间通信的宿主机上连接访问可通过以下命令:
2、如果是在没有做过容器间通信的服务器上连接访问则需要通过以下命令:
上文参考:
https://blog.csdn.net/tototuzuoquan/article/details/82119043
总结
以上关于如何做不同宿主机间容器通信和使用Docker创建虚拟机服务器我已经讲解的很清楚了,文中有些我是在网上找来的也添加了出处,在网上找来的内容我也有实际认认真真的研究过并且加以改进我才敢在我们的预生产环境使用。因为现在还没到真正的测试实验阶段,所以我不敢打包票说这些内容一定没有问题。
后续我会将遇到的问题整理进这篇文章的,如果我没有添加则说明确实没有问题了。看到这篇文章的人发现文中有问题可随时给我留言。最后说一句话,有些事情看着很容易,实际做起来你会发现也很容易,但得需要你去做啊。
版权声明:本文为CSDN博主「于先森2017」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yuliang123345/article/details/105799892
更多精彩推荐
☞华为副总裁回应应用删除用户图片;美国拟允许华为参与 5G 标准建设;Firefox 76.0 发布 | 极客头条